﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Infrastructure.Extensions;
using Infrastructure.Helper;
using Infrastructure.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using AspectCore.DynamicProxy;
using Infrastructure.Model.ApiResult;
using Infrastructure.Model.OperationModes;
using Infrastructure.Model.SideCar;

namespace Infrastructure.Attribute
{
    /// <summary>
    /// 边车模式拦截器属性
    /// 用于在方法执行前后注入SideCar模式的调用逻辑（类似AOP切面）
    /// Sidecar 的核心价值：分离关注点，让主应用更专注于业务逻辑。
    ///需要解耦非业务功能（如日志、监控、安全）。
    ///多语言混合技术栈。
    ///微服务架构（尤其是服务网格）。
    ///不适用场景：
    ///资源极度受限的环境（Sidecar 会增加内存/CPU 开销）。
    ///简单单体应用（可能过度设计）。
    ///Sidecar 是现代云原生架构的重要组成部分，尤其在 Kubernetes 和微服务中广泛应用。正确使用它可以显著提升系统的可维护性和扩展性。
    /// </summary>
    public class SideCarAttribute : AbstractInterceptorAttribute
    {
        // 依赖注入的配置项
        private readonly SideCarOption _options;

        // 日志记录器
        private readonly ILogger<SideCarAttribute> _logger;

        // SideCar模式（Before/After/Both）
        private readonly SideCarMode _SideCarMode;

        // 默认控制器名称（当未指定时使用反射获取）
        private readonly string _DefaultControllerName = "";

        // 默认方法名称（当未指定时使用反射获取）
        private readonly string _DefaultActionName = "";

        // 前置调用失败时是否继续执行
        private readonly bool _ProceedIfFailed;

        // 后置调用是否等待响应
        private readonly bool _WaitAfterReply;

        // HTTP上下文访问器（用于获取请求头等信息）
        private readonly IHttpContextAccessor _httpContextAccessor;

        /// <summary>
        /// 构造函数（通过依赖注入获取所需服务）
        /// </summary>
        /// <param name="SideCarMode">SideCar模式（默认Both：前后都执行）</param>
        /// <param name="ProceedIfFailed">前置失败处理策略（默认StopIfFailed：停止执行）</param>
        /// <param name="WaitAfterReply">后置调用等待策略（默认WaitForReply：等待响应）</param>
        /// <param name="DefaultControllerName">默认控制器名（优先使用反射获取）</param>
        /// <param name="DefaultActionName">默认方法名（优先使用反射获取）</param>
        public SideCarAttribute(
            SideCarMode SideCarMode = SideCarMode.Both,
            BeforeMode ProceedIfFailed = BeforeMode.StopIfFailed,
            AfterMode WaitAfterReply = AfterMode.WaitForReply,
            string DefaultControllerName = "",
            string DefaultActionName = "")
        {
            // 从全局服务容器获取依赖
            _httpContextAccessor = App.ServiceProvider.GetRequiredService<IHttpContextAccessor>();
            _options = App.ServiceProvider.GetRequiredService<IOptions<SideCarOption>>().Value;
            _logger = App.ServiceProvider.GetRequiredService<ILogger<SideCarAttribute>>();

            // 初始化配置参数
            _DefaultControllerName = DefaultControllerName;
            _DefaultActionName = DefaultActionName;
            _ProceedIfFailed = ProceedIfFailed == BeforeMode.ProceedIfFailed; // 转换为bool
            _WaitAfterReply = WaitAfterReply == AfterMode.WaitForReply;       // 转换为bool
            _SideCarMode = SideCarMode;
        }

        /// <summary>
        /// 拦截器核心方法（执行切面逻辑）
        /// </summary>
        /// <param name="context">切面上下文（包含方法参数等信息）</param>
        /// <param name="next">后续管道委托</param>
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            SideCarOrder sideCarOrder = SideCarOrder.Before; // 当前阶段标识

            // 获取控制器和方法名称（优先使用默认值）
            string ControllerName = StringExtension.IfEmptyThen(
                _DefaultControllerName,
                context.ServiceMethod.ReflectedType.Name);

            string ActionName = StringExtension.IfEmptyThen(
                _DefaultActionName,
                context.ServiceMethod.Name);

            try
            {
                // 初始化HTTP客户端工具（携带请求头）
                RestfulHelper restful = new RestfulHelper(GetHeader());
                string baseurl = _options.BaseUrl;

                /******************** 前置处理阶段 ********************/
                if (_SideCarMode != SideCarMode.OnlyAfter)
                {
                    _logger.LogInformation("正在执行服务调用前逻辑");

                    // 序列化所有输入参数
                    List<string> paramBefore = new List<string>();
                    foreach (object itm in context.Parameters)
                    {
                        paramBefore.Add(JsonConvert.SerializeObject(itm));
                    }

                    // 调用SideCar前置接口
                    ApiResult apiResultBefore = restful.Post("http://" + baseurl + "/api/" + ControllerName + "/" + ActionName + "_Before", null, JArray.FromObject((object)paramBefore));
                    // 处理前置调用结果
                    if (!apiResultBefore.IsSuccess)
                    {
                        if (!_ProceedIfFailed) // 配置为失败时停止
                        {
                            var ex = new SideCarException(
                                SideCarOrder.Before,
                                ActionName,
                                apiResultBefore.Msg);

                            _logger.LogWarning(ex.ToString());
                            throw ex; // 中断执行
                        }

                        // 配置为失败时继续
                        _logger.LogWarning($"前置调用失败但继续执行: {apiResultBefore.Msg}");
                    }
                }

                /******************** 执行原方法 ********************/
                await next.Invoke(context); // 执行被拦截的方法

                // 如果模式是OnlyBefore则直接返回
                if (_SideCarMode == SideCarMode.OnlyBefore) return;

                /******************** 后置处理阶段 ********************/
                sideCarOrder = SideCarOrder.After; // 切换阶段标识
                _logger.LogInformation("正在执行服务调用后逻辑");

                // 序列化参数（包含返回值）
                List<string> paramAfter = new List<string>();
                foreach (object itm2 in context.Parameters)
                {
                    paramAfter.Add(JsonConvert.SerializeObject(itm2));
                }
                paramAfter.Add(JsonConvert.SerializeObject(context.ReturnValue));

                // 根据等待策略处理
                if (_WaitAfterReply)
                {
                    // 同步调用并等待结果
                    ApiResult apiResultAfter = restful.Post(
                        $"http://{baseurl}/api/{ControllerName}/{ActionName}_After",
                        null,
                        JArray.FromObject(paramAfter));

                    if (!apiResultAfter.IsSuccess)
                    {
                        throw new SideCarException(
                            SideCarOrder.After,
                            ActionName,
                            apiResultAfter.Msg);
                    }
                    _logger.LogInformation("后置调用完成");
                }
                else
                {
                    // 异步调用不等待
                    restful.PostAsync(
                        $"http://{baseurl}/api/{ControllerName}/{ActionName}_After",
                        null,
                        JArray.FromObject(paramAfter));
                    _logger.LogInformation("已发起异步后置调用");
                }
            }
            catch (SideCarException) // 已知异常直接抛出
            {
                throw;
            }
            catch (Exception ex2) // 未知异常包装处理
            {
                _logger.LogWarning("SideCar未知错误");
                throw new SideCarException(
                    sideCarOrder,
                    ActionName,
                    "系统异常，请检查InnerException",
                    ex2);
            }
        }

        /// <summary>
        /// 构造请求头信息
        /// </summary>
        /// <returns>包含跟踪信息的Header字典</returns>
        private Dictionary<HeaderName, string> GetHeader()
        {
            var headers = new Dictionary<HeaderName, string>();

            // 获取分布式跟踪ID
            if (_httpContextAccessor.HttpContext.Request.Headers
                .TryGetValue(HeaderName.trace_id.ToString(), out var traceValue))
            {
                headers.Add(HeaderName.trace_id, traceValue);
            }

            // 获取父Span ID
            if (_httpContextAccessor.HttpContext.Request.Headers
                .TryGetValue(HeaderName.pspan_id.ToString(), out var pspanValue))
            {
                headers.Add(HeaderName.pspan_id, pspanValue);
            }

            // 获取当前用户Token
            var user = _httpContextAccessor.HttpContext.GetCurrentUserInfo();
            if (user != null)
            {
                headers.Add(HeaderName.auth_token, user.Token);
            }

            return headers;
        }
    }
}